#ifndef _UTILS_SYSTEM_HPP_
#define _UTILS_SYSTEM_HPP_
#include "stdafx.h"

namespace hhfox {

static bool deleteFile(const std::string& fname) {
    if (unlink(fname.c_str()) != 0) {
        return false;
    }
    return true;
}

static bool createDir(const std::string& name) {
    if (mkdir(name.c_str(), 0755) != 0) {
        return false;
    }
    return true;
}

static bool deleteDir(const std::string& name) {
    if (rmdir(name.c_str()) != 0) {
        return false;
    }
    return true;
}

static bool deleteDirRecursive(const std::string& path) {
    struct stat statbuf;
    if (stat(path.c_str(), &statbuf) != 0) {
        return false;
    }

    if (S_ISDIR(statbuf.st_mode)) {
        DIR* d = opendir(path.c_str());
        if (!d) {
            return false;
        }

        struct dirent* entry;
        while ((entry = readdir(d)) != nullptr) {
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
                continue;
            }

            std::string entryPath = path + "/" + entry->d_name;
            if (!deleteDirRecursive(entryPath)) {
                closedir(d);
                return false;
            }
        }
        closedir(d);

        if (rmdir(path.c_str()) != 0) {
            return false;
        }
    } else {
        if (unlink(path.c_str()) != 0) {
            return false;
        }
    }

    return true;
}

static bool fileExists(const std::string& fname) { return access(fname.c_str(), F_OK) == 0; }

static bool getChildren(const std::string& dir, std::vector<std::string>& result) {
    result.clear();
    DIR* d = opendir(dir.c_str());
    if (d == NULL) {
        return false;
    }
    struct dirent* entry;
    while ((entry = readdir(d)) != NULL) {
        result.push_back(entry->d_name);
    }
    closedir(d);
    return true;
}

static long long fileSize(const std::string& fname) {
    struct stat fileStat;
    if (stat(fname.c_str(), &fileStat) == 0) {
        return fileStat.st_size;
    }
    return -1;
}

#ifdef HAVE_ST_BIRTHTIME
#define birthtime(x) x.st_birthtime
#else
#define birthtime(x) x.st_ctime
#endif
static std::vector<std::string> getFileList(const char* dir, const char* prefix = "") {
    std::vector<std::string> lists;
    char path[256];
    DIR* dp;
    struct dirent* sdp;
    dp = opendir(dir);
    if (dp == NULL) {
        perror("opendir error");
        return lists;
    }
    while ((sdp = readdir(dp)) != NULL) {
        if (strcmp(sdp->d_name, ".") == 0 || strcmp(sdp->d_name, "..") == 0) {
            continue;
        }

        sprintf(path, "%s/%s", dir, sdp->d_name);
        struct stat sb;
        int ret = stat(path, &sb);
        if (ret == -1) {
            perror("stat error");
            continue;
        }
        if (S_ISREG(sb.st_mode)) {
            lists.push_back(std::string(prefix) + sdp->d_name);
        }
    }
    closedir(dp);
    auto compare = [&dir](const std::string& lhs, const std::string& rhs) {
        auto lpath = std::string(dir) + "/" + lhs;
        auto rpath = std::string(dir) + "/" + rhs;
        struct stat lsb, rsb;
        stat(lpath.c_str(), &lsb);
        stat(rpath.c_str(), &rsb);
        return birthtime(lsb) > birthtime(rsb);
    };

    std::sort(lists.begin(), lists.end(), compare);
    return lists;
}

static bool createDirIfNoExist(const std::string& name) {
    if (fileExists(name)) return true;
    return createDir(name);
}

static bool createDirRecursive(const std::string& path) {
    size_t pos = 0;
    while ((pos = path.find_first_of('/', pos)) != std::string::npos) {
        std::string subPath = path.substr(0, pos + 1);
        if (!fileExists(subPath)) {
            if (!createDir(subPath)) {
                return false;
            }
        }
        pos++;
    }
    // Create the final directory
    if (!fileExists(path)) {
        if (!createDir(path)) {
            return false;
        }
    }
    return true;
}

} // namespace hhfox

#endif